﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.IO;

namespace WpfGridlock
{
    /// <summary>
    /// Логика взаимодействия для GameWindow.xaml
    /// </summary>
    public partial class GameWindow : Window
    {
        public const int
            //задает ширину блоков
                       block_width = 60,
            // задание границы:
                       start_X_position = 0,
                       start_Y_position = 0,
                       width_window = 360,
                       height_window = 360;
        int N = 0; // задает количество блоков

        int[,] mas_of_block = new int[17, 4]; // массив хранящий расположение, координаты блоков и их длину
        int[,] record_mas = new int[25, 3]; // массив хранящий данные о рекордах

        bool IsClicked = false;
        double deltaX = 0, deltaY = 0;
        int count_rect = 0;

        int count_level = 0; // счетчик уровня
        int count_time = 0; // счетчик времени
        int count_moves = 0; // счетчик ходов

        int number_move_block = 0; // определяет номер движущегося блока
        int number_vstrechniy = 0; // определяет номер встречного блока
        int number_str_move_block = 0; // определяет номер строки в которой блок движется
        int number_column_move_block = 0; // определяет номер столбца, в которов блок движется
        int possibility_move = 0; // определяет возможность хода

        double[] raspologenie = new double[2]; // массив, определяюший вертик. или горизонтальный ли блок
        
        Rectangle[] rect = new Rectangle[18]; // мои прямоугольники
        System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer(); // создание таймера

        public GameWindow()
        {
            InitializeComponent();
            count_level = 1;
            label1.Content = count_level.ToString();

            timer.Tick += new EventHandler(tickTimer);
            timer.Interval = new TimeSpan(0, 0, 1);  // Секунда
            timer.Start();
        }

        private void ReturnMenuBtn_Click(object sender, RoutedEventArgs e)
        {
            MainWindow openWnew = new MainWindow();
            openWnew.Height = this.ActualHeight;
            openWnew.Width = this.ActualWidth;
            openWnew.WindowState = this.WindowState;
            openWnew.Show();
            this.Close(); // Закрываем текущую форму
        }

        /*ЧТЕНИЕ ДАННЫХ О РЕКОРДАХ*/
        private void Record_Read(int[,] record_array)
        {
            StreamReader sr = new StreamReader("Record.txt");
            string[] point = sr.ReadToEnd().Split('\n');
            string[] buffer;

            for (int i = 0; i < 25; i++)
            {
                buffer = point[i].Split(' ');
                for (int j = 0; j < 2; j++)
                {
                    record_array[i, j] = Convert.ToInt32(buffer[j]); // преобразуем в целочисленный тип
                }
            }

            ViewMoveLabel.Content = count_moves.ToString();
            ViewRecordMoveLabel.Content = (record_mas[count_level - 1, 0]).ToString();
            ViewRecordTimeLabel.Content = (record_mas[count_level - 1, 1]).ToString();
        }

        /*ВЫВОД ДАННЫХ О РЕКОРДАХ В ФАЙЛ*/
        private void Record_Write()
        {
            if (count_moves < record_mas[count_level - 1, 0]) record_mas[count_level - 1, 0] = count_moves;
            if (count_time < record_mas[count_level - 1, 1]) record_mas[count_level - 1, 1] = count_time;

            StreamWriter str = new StreamWriter("Record.txt");
            for (int i = 0; i < 25; i++)
            {
                string buff = record_mas[i, 0].ToString() + " " + record_mas[i, 1].ToString();
                str.WriteLine(buff);
            }
            str.Close();
        }

        /*ЧТЕНИЕ ДАННЫХ ИЗ ФАЙЛА*/
        private int Read(int[,] mas_block, string filename)
        {
            StreamReader sr = new StreamReader(filename);
            string k = sr.ReadLine();    //читаем первое число
            int number_of_blocks = Convert.ToInt32(k); // преобразуем

            string[] point = sr.ReadToEnd().Split('\n');

            string[] buffer;

            for (int i = 0; i < number_of_blocks; i++)
            {
                buffer = point[i].Split(' ');
                for (int j = 0; j < 4; j++)
                {
                    if (j == 1) mas_of_block[i, j] = Convert.ToInt32(buffer[j]);
                    else if (j == 2) mas_of_block[i, j] = Convert.ToInt32(buffer[j]);
                    else mas_of_block[i, j] = Convert.ToInt32(buffer[j]);
                }
            }
            return number_of_blocks;
        }

        internal void GetCountLevel(int count)
        {
            count_level = count;
            label1.Content = count_level.ToString();
        }

        private void canvas1_MouseDown(object sender, MouseButtonEventArgs e)
        {
            for (int j = 0; j < N; j++)
                if ((e.GetPosition(canvas1).X > Canvas.GetLeft(rect[j])) && (e.GetPosition(canvas1).X < Canvas.GetLeft(rect[j]) + rect[j].Width) &&
                        (e.GetPosition(canvas1).Y < Canvas.GetTop(rect[j]) + rect[j].Height) && (e.GetPosition(canvas1).Y > Canvas.GetTop(rect[j])))
                {
                    IsClicked = true;
                    deltaX = e.GetPosition(canvas1).X - Canvas.GetLeft(rect[j]);
                    deltaY = e.GetPosition(canvas1).Y - Canvas.GetTop(rect[j]);
                    number_move_block = j;
                    break;
                }
        }

        private void canvas1_MouseUp(object sender, MouseButtonEventArgs e)
        {
            IsClicked = false;

            correct_location_func();
            
            /*ПОБЕДА!!!*/
            if (Canvas.GetLeft(rect[0]) >= canvas1.Width - 2 * block_width)
            {
                Canvas.SetLeft(rect[0], canvas1.Width - block_width);
                timer.Stop();

                // функция записи рекордов
                Record_Write();
                GameWindow openWnew = new GameWindow();
                openWnew.GetCountLevel(count_level + 1);
                openWnew.Height = this.Height;
                openWnew.Width = this.Width;
                openWnew.WindowState = this.WindowState;
                openWnew.Show();
                this.Close();  // Закрываем текущую форму
            }
            ViewMoveLabel.Content = count_moves.ToString();
        }

        /*ОПРЕДЕЛЕНИЕ КООРДИНАТ ПРЯМОУГОЛЬНИКОВ*/
          private void Build_Rectangle(int[,] a, ref Rectangle[] rect)
          {
              for (int i = 0; i < N; i++)
              {
                  if ((a[i, 0] == 1) && (count_rect < N))
                  {
                      rect[count_rect] = new Rectangle();
                      rect[count_rect].Width = a[i, 3] * block_width;
                      rect[count_rect].Height = block_width;
                      rect[count_rect].StrokeThickness = 2;

                      if (i == 0)
                      {
                          ImageBrush myBrush = new ImageBrush();
                          myBrush.ImageSource = new BitmapImage(new Uri(@"PH01.jpg", UriKind.Relative));
                          rect[count_rect].Fill = myBrush;
                          rect[count_rect].Stroke = new SolidColorBrush(Colors.Black);
                      }
                      else
                      {
                          ImageBrush myBrush = new ImageBrush();
                          myBrush.ImageSource = new BitmapImage(new Uri(@"PH02.jpg", UriKind.Relative));
                          rect[count_rect].Fill = myBrush;
                          rect[count_rect].Stroke = new SolidColorBrush(Colors.Black);
                      }

                      // Set Canvas position
                      Canvas.SetLeft(rect[count_rect], a[i, 1]*block_width);
                      Canvas.SetTop(rect[count_rect], a[i, 2] * block_width);
                      // Add Rectangle to Canvas
                      canvas1.Children.Add(rect[count_rect]);  
                      count_rect++;
                  }
                  else if ((a[i, 0] == 2) && (count_rect < N))
                  {
                      rect[count_rect] = new Rectangle();
                      rect[count_rect].Width = block_width;
                      rect[count_rect].Height = a[i, 3] * block_width;
                      rect[count_rect].Stroke = new SolidColorBrush(Colors.Black);

                      rect[count_rect].StrokeThickness = 2;
                      ImageBrush myBrush = new ImageBrush();
                      myBrush.ImageSource = new BitmapImage(new Uri(@"PH03.jpg", UriKind.Relative));
                      rect[count_rect].Fill = myBrush;
                      Canvas.SetLeft(rect[count_rect], a[i, 1] * block_width);
                      Canvas.SetTop(rect[count_rect], a[i, 2] * block_width);
                      canvas1.Children.Add(rect[count_rect]);
                      count_rect++;
                  }
              }
          } 

        private void canvas1_Loaded(object sender, RoutedEventArgs e)
        {
            if (count_level == 1) Lastbutton.Visibility = System.Windows.Visibility.Hidden;
            else if (count_level == 25) Nextbutton.Visibility = System.Windows.Visibility.Hidden;

            string filename_level = @"maps\map" + count_level + ".txt";
            // чтение количества прямоугольников и всех измерений,
            // необходимых для построения блоков

            /*ОТРИСОВКА ИГРОВЫХ БЛОКОВ*/
            N = Read(mas_of_block, filename_level);
            Build_Rectangle(mas_of_block, ref rect); // определяем координаты прямоугольников
            Record_Read(record_mas);
        }

        private void canvas1_MouseMove(object sender, MouseEventArgs e)
        {
            /*ПРОВЕРКА ГРАНИЦ И ПЕРЕМЕЩЕНИЕ ПО ИГРОВОМУ ПОЛЮ*/
            number_vstrechniy = 0;

            if (IsClicked)
            {
                move_blocks_func(raspologenie, e.GetPosition(canvas1).X, e.GetPosition(canvas1).Y);

                if (mas_of_block[number_move_block, 0] == 1) // условие горизонтальности блока
                {
                    // определим номер строки, в которой движется блок
                    number_str_move_block = mas_of_block[number_move_block, 2];

                    if ((raspologenie[0] >= start_X_position) && (raspologenie[0] <= (canvas1.Width + start_X_position - rect[number_move_block].Width))) // проверка границ игровой коробки
                    {
                        //если двигаемся вправо

                        if (Canvas.GetLeft(rect[number_move_block]) < raspologenie[0]) //вправо
                        {
                            // определим блок, самый близкий по X к движимому блоку в данной строке
                            double minX = canvas1.Width;

                            for (int k = 0; k < N; k++)
                            {
                                if (k != number_move_block)
                                {
                                    // если встречный блок вертикальный
                                    if (mas_of_block[k, 0] == 2)
                                    {
                                        // если сверху или в строке есть встречный блок
                                        if (Canvas.GetTop(rect[number_move_block]) >= Canvas.GetTop(rect[k]))
                                        {
                                            if (Math.Abs(Canvas.GetTop(rect[number_move_block]) - Canvas.GetTop(rect[k])) < rect[k].Height)
                                            {
                                                if (Canvas.GetLeft(rect[number_move_block]) + rect[number_move_block].Width <= Canvas.GetLeft(rect[k])) // справа
                                                {
                                                    if (Canvas.GetLeft(rect[k]) <= minX)
                                                    {
                                                        minX = Canvas.GetLeft(rect[k]);
                                                        number_vstrechniy = k;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    // если встречный блок горизонтальный
                                    else if (mas_of_block[k, 0] == 1)
                                    {
                                        if (Canvas.GetTop(rect[k]) == Canvas.GetTop(rect[number_move_block]))
                                        {
                                            if (Canvas.GetLeft(rect[number_move_block]) + rect[number_move_block].Width <= Canvas.GetLeft(rect[k])) // справа
                                            {
                                                if (Canvas.GetLeft(rect[k]) <= minX)
                                                {
                                                    minX = Canvas.GetLeft(rect[k]);
                                                    number_vstrechniy = k;
                                                }
                                            }
                                        }
                                    }  
                                }
                            }
                            if (minX == start_X_position + canvas1.Width)
                            {
                                Canvas.SetLeft(rect[number_move_block], raspologenie[0]);
                                possibility_move = 1;
                            }
                            else if (raspologenie[0] + rect[number_move_block].Width < Canvas.GetLeft(rect[number_vstrechniy]))
                            {
                                Canvas.SetLeft(rect[number_move_block], raspologenie[0]);
                                possibility_move = 1;
                            }
                        }

                        // если двигаемся влево
                        else if (Canvas.GetLeft(rect[number_move_block]) > raspologenie[0]) //влево
                        {
                            // определим блок, самый близкий по X к движимому блоку в данной строке
                            double maxX = start_X_position;
                            int flag = 0;

                            for (int k = 0; k < N; k++)
                            {
                                if (k != number_move_block)
                                {
                                    // если встречный блок вертикальный
                                    if (mas_of_block[k, 0] == 2)
                                    {
                                        // если сверху или в строке есть встречный блок
                                        if (Canvas.GetTop(rect[number_move_block]) >= Canvas.GetTop(rect[k]))
                                        {
                                            if (Math.Abs(Canvas.GetTop(rect[number_move_block]) - Canvas.GetTop(rect[k])) < rect[k].Height)
                                            {
                                                if (Canvas.GetLeft(rect[number_move_block]) >= Canvas.GetLeft(rect[k]) + block_width) // слева  !!!!!!!!!!!!!!!!!!вместо block_width было написано 70
                                                {
                                                    if (Canvas.GetLeft(rect[k]) >= maxX)
                                                    {
                                                        maxX = Canvas.GetLeft(rect[k]);
                                                        flag = 1;
                                                        number_vstrechniy = k;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    // если встречный блок горизонтальный
                                    else if (mas_of_block[k, 0] == 1)
                                    {
                                        if (Canvas.GetTop(rect[k]) == Canvas.GetTop(rect[number_move_block]))
                                        {
                                            if (Canvas.GetLeft(rect[number_move_block]) >= Canvas.GetLeft(rect[k]) + rect[k].Width) // слева
                                            {
                                                if (Canvas.GetLeft(rect[k]) >= maxX)
                                                {
                                                    maxX = Canvas.GetLeft(rect[k]);
                                                    flag = 1;
                                                    number_vstrechniy = k;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            if ((maxX == start_X_position) && (flag == 0))
                            {
                                Canvas.SetLeft(rect[number_move_block], raspologenie[0]);
                                possibility_move = 1;
                            }
                            else if (raspologenie[0] > Canvas.GetLeft(rect[number_vstrechniy]) + rect[number_vstrechniy].Width)
                            {
                                Canvas.SetLeft(rect[number_move_block], raspologenie[0]);
                                possibility_move = 1;
                            }
                        }
                    }

                }
                else if (mas_of_block[number_move_block, 0] == 2) // условие вертикальности блока
                {
                       // определим номер столбца, в котором движется блок
                        number_column_move_block = mas_of_block[number_move_block, 1];

                        if ((raspologenie[1] >= start_Y_position) && (raspologenie[1] <=
                            (canvas1.Height + start_Y_position - rect[number_move_block].Height))) // 
                        {
                            //если двигаемся вниз

                            if (Canvas.GetTop(rect[number_move_block]) < raspologenie[1]) //вниз
                            {
                                // определим блок, самый близкий по Y к движимому блоку в данной строке
                                double minX = start_Y_position + height_window;
                                for (int k = 0; k < N; k++)
                                {
                                    if (k != number_move_block)
                                    {
                                        // если встречный блок горизонтальный
                                        if (mas_of_block[k, 0] == 1)
                                        {
                                            if (Canvas.GetLeft(rect[number_move_block]) >= Canvas.GetLeft(rect[k])) // если сбоку или в столбце есть встречный блок
                                            {
                                                if (Math.Abs(Canvas.GetLeft(rect[number_move_block]) - Canvas.GetLeft(rect[k])) < rect[k].Width)
                                                {
                                                    if (Canvas.GetTop(rect[number_move_block]) + rect[number_move_block].Height <= Canvas.GetTop(rect[k])) // сверху
                                                    {
                                                        if (Canvas.GetTop(rect[k]) <= minX)
                                                        {
                                                            minX = Canvas.GetTop(rect[k]);
                                                            number_vstrechniy = k;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        // если встречный блок вертикальный
                                        else if (mas_of_block[k, 0] == 2)
                                        {
                                            if (Canvas.GetLeft(rect[k]) == Canvas.GetLeft(rect[number_move_block]))
                                            {
                                                if (Canvas.GetTop(rect[number_move_block]) + rect[number_move_block].Height <= Canvas.GetTop(rect[k])) // сверху
                                                {
                                                    if (Canvas.GetTop(rect[k]) <= minX)
                                                    {
                                                        minX = Canvas.GetTop(rect[k]);
                                                        number_vstrechniy = k;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                if (minX == start_Y_position + height_window)
                                {
                                    Canvas.SetTop(rect[number_move_block], raspologenie[1]) ;
                                    possibility_move = 1;
                                    //pictureBox.Invalidate();
                                }
                                else if (raspologenie[1] + rect[number_move_block].Height < Canvas.GetTop(rect[number_vstrechniy]))
                                {
                                    Canvas.SetTop(rect[number_move_block], raspologenie[1]);
                                    possibility_move = 1;
                                    //pictureBox.Invalidate();
                                }
                            }
                            // если двигаемся вверх
                            else if (Canvas.GetTop(rect[number_move_block]) > raspologenie[1]) //вверх
                            {

                                // определим блок, самый близкий по X к движимому блоку в данной строке
                                double maxX = start_Y_position;
                                int flag = 0;
                                for (int k = 0; k < N; k++)
                                {
                                    if (k != number_move_block)
                                    {
                                        // если встречный блок горизонтальный
                                        if (mas_of_block[k, 0] == 1)
                                        {
                                            // если сбоку или в столбце есть встречный блок
                                            if (Canvas.GetLeft(rect[number_move_block]) >= Canvas.GetLeft(rect[k]))
                                            {
                                                if (Math.Abs(Canvas.GetLeft(rect[number_move_block]) - Canvas.GetLeft(rect[k])) < rect[k].Width)
                                                {
                                                    if (Canvas.GetTop(rect[number_move_block]) >= Canvas.GetTop(rect[k]) + block_width) // снизу
                                                    {
                                                        if (Canvas.GetTop(rect[k]) >= maxX)
                                                        {
                                                            maxX = Canvas.GetTop(rect[k]);
                                                            flag = 1;
                                                            number_vstrechniy = k;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        // если встречный блок вертикальный
                                        else if (mas_of_block[k, 0] == 2)
                                        {
                                            if (Canvas.GetLeft(rect[k]) == Canvas.GetLeft(rect[number_move_block]))
                                            {
                                                if (Canvas.GetTop(rect[number_move_block]) >= Canvas.GetTop(rect[k]) + rect[k].Height) // снизу
                                                {
                                                    if (Canvas.GetTop(rect[k]) >= maxX)
                                                    {
                                                        maxX = Canvas.GetTop(rect[k]);
                                                        flag = 1;
                                                        number_vstrechniy = k;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                if ((maxX == start_Y_position) && (flag == 0))
                                {
                                    Canvas.SetTop(rect[number_move_block], raspologenie[1]);
                                    possibility_move = 1;
                                }
                                else if (raspologenie[1] > Canvas.GetTop(rect[number_vstrechniy]) + rect[number_vstrechniy].Height)
                                {
                                    Canvas.SetTop(rect[number_move_block], raspologenie[1]);
                                    possibility_move = 1;
                                }
                            }
                        }

                    }
                }
            }

        private void move_blocks_func(double[] a, double current_loc_X, double current_loc_Y)
        {
            a[0] = current_loc_X - deltaX;
            a[1] = current_loc_Y - deltaY;
        }

        private void Nextbutton_Click(object sender, RoutedEventArgs e)
        {
            if (count_level != 25)
            {
                count_rect = 0;
                count_moves = 0;
                count_time = 0;
                count_level += 1;
                GameWindow openWnew = new GameWindow();
                openWnew.GetCountLevel(count_level);
                openWnew.Height = this.ActualHeight;
                openWnew.Width = this.ActualWidth;
                openWnew.WindowState = this.WindowState;
                openWnew.Show();
                this.Close();  // Закрываем текущую форму
            }
        }

        private void Lastbutton_Click(object sender, RoutedEventArgs e)
        {
            if (count_level != 1)
            {
                count_rect = 0;
                count_moves = 0;
                count_time = 0;
                count_level -= 1;
                GameWindow openWnew = new GameWindow();
                openWnew.GetCountLevel(count_level);
                openWnew.Height = this.ActualHeight;
                openWnew.Width = this.ActualWidth;
                openWnew.WindowState = this.WindowState;
                openWnew.Show();
                this.Close();  // Закрываем текущую форму
            }
        } 

        private void correct_location_func()
        {
            if (possibility_move == 1)
            {
                if (mas_of_block[number_move_block, 0] == 1)
                {
                    for (int i = 1; i < 5; i++) 
                        if ((Canvas.GetLeft(rect[number_move_block]) > (i-1) * block_width) 
                            && (Canvas.GetLeft(rect[number_move_block]) <= i*block_width - block_width/2))
                        {
                            Canvas.SetLeft(rect[number_move_block],(i-1) * block_width);
                            count_moves++;
                            possibility_move = 0;
                        }
                        else if ((Canvas.GetLeft(rect[number_move_block]) < i*block_width) 
                            && (Canvas.GetLeft(rect[number_move_block]) > (i-1) * block_width + block_width/2))
                        {
                            Canvas.SetLeft(rect[number_move_block], i*block_width);
                            count_moves++;
                            possibility_move = 0;
                        }
                }
                else if (mas_of_block[number_move_block, 0] == 2)
                {
                    for (int i = 1; i < 5; i++)
                        if ((Canvas.GetTop(rect[number_move_block]) <= i*block_width - block_width/2) 
                            && (Canvas.GetTop(rect[number_move_block]) > (i-1)*block_width))
                        {
                            Canvas.SetTop(rect[number_move_block],(i-1)*block_width);
                            count_moves++;
                            possibility_move = 0;
                        }
                        else if ((Canvas.GetTop(rect[number_move_block]) < i * block_width) 
                            && (Canvas.GetTop(rect[number_move_block]) > (i-1)*block_width + block_width/2))
                        {
                            Canvas.SetTop(rect[number_move_block], i * block_width);
                            count_moves++;
                            possibility_move = 0;
                        }
                }
            }
        } 

        /*ТАЙМЕР*/
        private void tickTimer(object sender, EventArgs e)
        {
            count_time += 1;
            ViewTimeLabel.Content = count_time.ToString();
        }

        private void Regamebutton_Click(object sender, RoutedEventArgs e)
        {
            GameWindow openWnew = new GameWindow();
            openWnew.GetCountLevel(count_level);
            openWnew.Height = this.ActualHeight;
            openWnew.Width = this.ActualWidth;
            openWnew.WindowState = this.WindowState;
            openWnew.Show();
            this.Close();  // Закрываем текущую форму
        }
    }
}